// *
// * Copyright (C) 2008 Roger Alsing : http://www.RogerAlsing.com
// *
// * This library is free software; you can redistribute it and/or modify it
// * under the terms of the GNU Lesser General Public License 2.1 or later, as
// * published by the Free Software Foundation. See the included license.txt
// * or http://www.gnu.org/copyleft/lesser.html for details.
// *
// *
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Web;
using System.Windows.Forms;
using Alsing.Drawing.GDI;
using Alsing.Windows.Forms.FormatLabel;

namespace Alsing.Windows.Forms.CoreLib
{
    /// <summary>
    /// 
    /// </summary>
    public class FormatLabelControl : BaseControl
    {
        private readonly Dictionary<string, GDIFont> _Fonts = new Dictionary<string, GDIFont>();
        private Element _ActiveElement;
        private Element[] _Elements;
        private bool _HasImageError;
        private ImageList _ImageList;
        private Color _Link_Color = Color.Blue;
        private Color _Link_Color_Hover = Color.Blue;
        private bool _Link_UnderLine;
        private bool _Link_UnderLine_Hover = true;
        private List<Row> _Rows;
        private ScrollBars _ScrollBars = 0;
        private string _Text = "format <b>label</b>";
        private bool _WordWrap = true;
        private PictureBox Filler;
        private HScrollBar hScroll;
        private VScrollBar vScroll;
        public ImageList ImageList
        {
            get { return this._ImageList; }
            set
            {
                this._ImageList = value;
                this.Invalidate();
                //this.Text = this.Text;
            }
        }
        public Color Link_Color
        {
            get { return this._Link_Color; }
            set
            {
                this._Link_Color = value;
                this.Invalidate();
            }
        }
        public Color Link_Color_Hover
        {
            get { return this._Link_Color_Hover; }
            set
            {
                this._Link_Color_Hover = value;
                this.Invalidate();
            }
        }
        public bool Link_UnderLine
        {
            get { return this._Link_UnderLine; }
            set
            {
                this._Link_UnderLine = value;
                this.Invalidate();
            }
        }
        public bool Link_UnderLine_Hover
        {
            get { return this._Link_UnderLine_Hover; }
            set
            {
                this._Link_UnderLine_Hover = value;
                this.Invalidate();
            }
        }
        public bool AutoSizeHorizontal { get; set; }
        public bool AutoSizeVertical { get; set; }
        public bool WordWrap
        {
            get { return this._WordWrap; }
            set
            {
                this._WordWrap = value;
                this.CreateRows();
                this.Invalidate();
            }
        }
        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always), Obsolete("", false)]
        public override Image BackgroundImage
        {
            get { return base.BackgroundImage; }
            set { base.BackgroundImage = value; }
        }
        public ScrollBars ScrollBars
        {
            get { return this._ScrollBars; }
            set
            {
                this._ScrollBars = value;
                this.InitScrollbars();
            }
        }

        #region Defaults
        private Container components;
        public FormatLabelControl()
        {
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.Opaque, true);
            this.InitializeComponent();
            this.Text = this.Text;
        }
        protected override void Dispose(bool disposing)
        {
            if(disposing){
                foreach(GDIObject o in this._Fonts.Values){
                    o.Dispose();
                }
                if(this.components != null){
                    this.components.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code
        [Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public override string Text
        {
            get { return _Text; }
            set
            {
                try{
                    //Text=value;
                    _Text = value;
                    CreateAll();
                    this.Invalidate();
                } catch(Exception x){
                    Console.WriteLine(x.Message);
                    System.Diagnostics.Debugger.Break();
                }
            }
        }
        /// <summary>
        /// Required method for Designer support - do not modify 
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.Filler = new System.Windows.Forms.PictureBox();
            this.vScroll = new System.Windows.Forms.VScrollBar();
            this.hScroll = new System.Windows.Forms.HScrollBar();
            this.SuspendLayout();
            // 
            // Filler
            // 
            this.Filler.BackColor = System.Drawing.SystemColors.Control;
            this.Filler.Cursor = System.Windows.Forms.Cursors.Default;
            this.Filler.Location = new System.Drawing.Point(136, 112);
            this.Filler.Name = "Filler";
            this.Filler.Size = new System.Drawing.Size(16, 16);
            this.Filler.TabIndex = 5;
            this.Filler.TabStop = false;
            // 
            // vScroll
            // 
            this.vScroll.Cursor = System.Windows.Forms.Cursors.Default;
            this.vScroll.LargeChange = 2;
            this.vScroll.Location = new System.Drawing.Point(136, -8);
            this.vScroll.Name = "vScroll";
            this.vScroll.Size = new System.Drawing.Size(16, 112);
            this.vScroll.TabIndex = 4;
            this.vScroll.Scroll += new System.Windows.Forms.ScrollEventHandler(this.vScroll_Scroll);
            // 
            // hScroll
            // 
            this.hScroll.Cursor = System.Windows.Forms.Cursors.Default;
            this.hScroll.LargeChange = 1;
            this.hScroll.Location = new System.Drawing.Point(0, 112);
            this.hScroll.Maximum = 600;
            this.hScroll.Name = "hScroll";
            this.hScroll.Size = new System.Drawing.Size(128, 16);
            this.hScroll.TabIndex = 3;
            // 
            // FormatLabelControl
            // 
            this.BackColor = System.Drawing.SystemColors.Window;
            this.Controls.AddRange(new System.Windows.Forms.Control[]{this.Filler, this.vScroll, this.hScroll});
            this.Name = "FormatLabelControl";
            this.Size = new System.Drawing.Size(160, 136);
            this.ResumeLayout(false);
        }
        private void CreateAll()
        {
            _Elements = CreateElements();
            ClearFonts();
            ApplyFormat(_Elements);
            CreateWords(_Elements);
            CreateRows();
            SetAutoSize();
        }
        private void ClearFonts()
        {
            foreach(GDIFont gf in _Fonts.Values){
                gf.Dispose();
            }
            _Fonts.Clear();
        }
        #endregion

        #endregion

        public event ClickLinkEventHandler ClickLink = null;
        protected void OnClickLink(string Link)
        {
            if(this.ClickLink != null){
                this.ClickLink(this, new ClickLinkEventArgs(Link));
            }
        }
        private void SetAutoSize()
        {
            if(this.AutoSizeHorizontal){
                this.Width = this.GetWidth();
            }
            if(this.AutoSizeVertical){
                this.Height = this.GetHeight();
            }
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            this.SetAutoSize();
            //base.OnPaint (e);
            if(this._HasImageError){
                this.CreateAll();
            }
            var bbuff = new GDISurface(this.Width, this.Height, this, true);
            Graphics g = Graphics.FromHdc(bbuff.hDC);
            try{
                bbuff.FontTransparent = true;
                if(this.BackgroundImage != null){
                    g.DrawImage(this.BackgroundImage, 0, 0, this.Width, this.Height);
                } else{
                    bbuff.Clear(this.BackColor);
                }
                int x = this.Margin;
                int y = this.Margin;
                for(int i = this.vScroll.Value; i < this._Rows.Count; i++){
                    Row r = this._Rows[i];
                    x = this.Margin;
                    r.Visible = true;
                    r.Top = y;
                    if(r.RenderSeparator){
                        Color c1 = Color.FromArgb(120, 0, 0, 0);
                        Brush b1 = new SolidBrush(c1);
                        g.FillRectangle(b1, 0, y, this.Width, 1);
                        Color c2 = Color.FromArgb(120, 255, 255, 255);
                        Brush b2 = new SolidBrush(c2);
                        g.FillRectangle(b2, 0, y + 1, this.Width, 1);
                        b1.Dispose();
                        b2.Dispose();
                        //bbuff.DrawLine (this.ForeColor,new Point (0,y),new Point (this.Width,y));
                    }
                    foreach(Word w in r.Words){
                        int ypos = r.Height - w.Height + y;
                        if(w.Image != null){
                            g.DrawImage(w.Image, x, y);
                            //bbuff.FillRect (Color.Red ,x,ypos,w.Width ,w.Height);
                        } else{
                            GDIFont gf;
                            if(w.Element.Link != null){
                                Font f = null;
                                FontStyle fs = w.Element.Font.Style;
                                if(w.Element.Link == this._ActiveElement){
                                    if(this._Link_UnderLine_Hover){
                                        fs |= FontStyle.Underline;
                                    }
                                    f = new Font(w.Element.Font, fs);
                                } else{
                                    if(this._Link_UnderLine){
                                        fs |= FontStyle.Underline;
                                    }
                                    f = new Font(w.Element.Font, fs);
                                }
                                gf = this.GetFont(f);
                            } else{
                                gf = this.GetFont(w.Element.Font);
                            }
                            bbuff.Font = gf;
                            if(w.Element.Effect != TextEffect.None){
                                bbuff.TextForeColor = w.Element.EffectColor;
                                if(w.Element.Effect == TextEffect.Outline){
                                    for(int xx = -1; xx <= 1; xx++){
                                        for(int yy = -1; yy <= 1; yy++){
                                            bbuff.DrawTabbedString(w.Text, x + xx, ypos + yy, 0, 0);
                                        }
                                    }
                                } else if(w.Element.Effect != TextEffect.None){
                                    bbuff.DrawTabbedString(w.Text, x + 1, ypos + 1, 0, 0);
                                }
                            }
                            if(w.Element.Link != null){
                                if(w.Element.Link == this._ActiveElement){
                                    bbuff.TextForeColor = this.Link_Color_Hover;
                                } else{
                                    bbuff.TextForeColor = this.Link_Color;
                                }
                            } else{
                                bbuff.TextForeColor = w.Element.ForeColor;
                            }
                            bbuff.TextBackColor = w.Element.BackColor;
                            bbuff.DrawTabbedString(w.Text, x, ypos, 0, 0);
                        }
                        w.ScreenArea.X = x;
                        w.ScreenArea.Y = ypos;
                        x += w.Width;
                    }
                    y += r.Height + r.BottomPadd;
                    if(y > this.Height){
                        break;
                    }
                }
            } catch(Exception x){
                Console.WriteLine(x.Message);
            }
            bbuff.RenderToControl(0, 0);
            bbuff.Dispose();
            g.Dispose();
        }
        private Element[] CreateElements()
        {
            string text = this.Text.Replace("\n", "");
            text = text.Replace("\r", "");
            string[] parts = text.Split('<');
            var elements = new List<Element>();
            int i = 0;
            foreach(string part in parts){
                var cmd = new Element();
                if(i == 0){
                    cmd.Text = part;
                } else{
                    string[] TagTextPair = part.Split('>');
                    cmd.Tag = TagTextPair[0].ToLowerInvariant();
                    if(cmd.Tag.IndexOfAny(" \t".ToCharArray()) >= 0){
                        int ws = cmd.Tag.IndexOfAny(" \t".ToCharArray());
                        string s1 = TagTextPair[0].Substring(0, ws).ToLowerInvariant();
                        string s2 = TagTextPair[0].Substring(ws + 1);
                        cmd.Tag = s1 + " " + s2;
                    }
                    cmd.Text = TagTextPair[1];
                    if(cmd.TagName == "img"){
                        var img = new Element{Tag = cmd.Tag};
                        elements.Add(img);
                        cmd.Tag = "";
                        //	Elements.Add (cmd);					
                    }
                    //
                    //					if (cmd.TagName == "hr")
                    //					{
                    //						Element hr=new Element();
                    //						hr.Tag = cmd.Tag;					
                    //						Elements.Add (hr);
                    //						cmd.Tag ="";
                    //						cmd.Text ="a";
                    //						//	Elements.Add (cmd);					
                    //					}
                    cmd.Text = cmd.Text.Replace("\t", "     ");
                    cmd.Text = cmd.Text.Replace("&#145;", "'");
                    cmd.Text = cmd.Text.Replace("&#146;", "'");
                    cmd.Text = cmd.Text.Replace(" ", ((char)1).ToString());
                    cmd.Text = HttpUtility.HtmlDecode(cmd.Text);
                    //	cmd.Text =cmd.Text.Replace (" ","*");
                    cmd.Text = cmd.Text.Replace(((char)1).ToString(), " ");
                }
                elements.Add(cmd);
                i++;
            }
            var res = new Element[elements.Count];
            elements.CopyTo(res);
            return res;
        }
        private string GetAttrib(string attrib, string tag)
        {
            try{
                if(tag.IndexOf(attrib) < 0){
                    return "";
                }
                //tag=tag.Replace("\"","");
                tag = tag.Replace("\t", " ");
                int start = tag.IndexOf(attrib);
                int end = start + attrib.Length;
                int valuestart = tag.IndexOf("=", end);
                if(valuestart < 0){
                    return "";
                }
                valuestart++;
                string value = tag.Substring(valuestart);
                while(value.StartsWith(" ")){
                    value = value.Substring(1);
                }
                //int pos=0;
                if(value.StartsWith("\"")){
                    // = "value"
                    value = value.Substring(1);
                    int valueend = value.IndexOf("\"");
                    value = value.Substring(0, valueend);
                    return value;
                } else{
                    // = value
                    int valueend = value.IndexOf(" ");
                    if(valueend < 0){
                        valueend = value.Length;
                    }
                    value = value.Substring(0, valueend);
                    return value;
                }
                //return "";
            } catch{
                return "";
            }
        }
        private void ApplyFormat(Element[] Elements)
        {
            var bold = new Stack();
            var italic = new Stack();
            var underline = new Stack();
            var forecolor = new Stack();
            var backcolor = new Stack();
            var fontsize = new Stack();
            var fontname = new Stack();
            var link = new Stack();
            var effectcolor = new Stack();
            var effect = new Stack();
            bold.Push(this.Font.Bold);
            italic.Push(this.Font.Italic);
            underline.Push(this.Font.Underline);
            forecolor.Push(this.ForeColor);
            backcolor.Push(Color.Transparent);
            fontsize.Push((int)(this.Font.Size * 1.3));
            fontname.Push(this.Font.Name);
            effect.Push(TextEffect.None);
            effectcolor.Push(Color.Black);
            link.Push(null);
            foreach(Element Element in Elements){
                switch(Element.TagName){
                    case "b":
                    {
                        bold.Push(true);
                        break;
                    }
                    case "a":
                    {
                        //underline.Push (true);
                        //forecolor.Push (_l);
                        link.Push(Element);
                        break;
                    }
                    case "i":
                    case "em":
                    {
                        italic.Push(true);
                        break;
                    }
                    case "u":
                    {
                        underline.Push(true);
                        break;
                    }
                    case "font":
                    {
                        string _fontname = this.GetAttrib("face", Element.Tag);
                        string _size = this.GetAttrib("size", Element.Tag);
                        string _color = this.GetAttrib("color", Element.Tag);
                        string _effectcolor = this.GetAttrib("effectcolor", Element.Tag);
                        string _effect = this.GetAttrib("effect", Element.Tag);
                        if(_size == ""){
                            fontsize.Push(fontsize.Peek());
                        } else{
                            fontsize.Push(int.Parse(_size));
                        }
                        if(_fontname == ""){
                            fontname.Push(fontname.Peek());
                        } else{
                            fontname.Push(_fontname);
                        }
                        if(_color == ""){
                            forecolor.Push(forecolor.Peek());
                        } else{
                            forecolor.Push(Color.FromName(_color));
                        }
                        if(_effectcolor == ""){
                            effectcolor.Push(effectcolor.Peek());
                        } else{
                            effectcolor.Push(Color.FromName(_effectcolor));
                        }
                        if(_effect == ""){
                            effect.Push(effect.Peek());
                        } else{
                            effect.Push(Enum.Parse(typeof(TextEffect), _effect, true));
                        }
                        break;
                    }
                    case "br":
                    {
                        Element.NewLine = true;
                        break;
                    }
                    case "hr":
                    {
                        Element.NewLine = true;
                        break;
                    }
                    case "h3":
                    {
                        fontsize.Push((int)(this.Font.Size * 1.4));
                        bold.Push(true);
                        Element.NewLine = true;
                        break;
                    }
                    case "h4":
                    {
                        fontsize.Push((int)(this.Font.Size * 1.2));
                        bold.Push(true);
                        Element.NewLine = true;
                        break;
                    }
                    case "/b":
                    {
                        bold.Pop();
                        break;
                    }
                    case "/a":
                    {
                        //underline.Pop ();
                        //forecolor.Pop ();
                        link.Pop();
                        break;
                    }
                    case "/i":
                    case "/em":
                    {
                        italic.Pop();
                        break;
                    }
                    case "/u":
                    {
                        underline.Pop();
                        break;
                    }
                    case "/font":
                    {
                        fontname.Pop();
                        fontsize.Pop();
                        forecolor.Pop();
                        effect.Pop();
                        effectcolor.Pop();
                        break;
                    }
                    case "/h3":
                    {
                        fontsize.Pop();
                        bold.Pop();
                        Element.NewLine = true;
                        break;
                    }
                    case "/h4":
                    {
                        fontsize.Pop();
                        bold.Pop();
                        Element.NewLine = true;
                        break;
                    }
                    default:
                    {
                        break;
                    }
                }
                //---------------------------------------------------------------------
                var Bold = (bool)bold.Peek();
                var Italic = (bool)italic.Peek();
                var Underline = (bool)underline.Peek();
                var Link = (Element)link.Peek();
                var FontName = (string)fontname.Peek();
                var FontSize = (int)fontsize.Peek();
                var BackColor = (Color)backcolor.Peek();
                var ForeColor1 = (Color)forecolor.Peek();
                var Effect = (TextEffect)effect.Peek();
                var EffectColor = (Color)effectcolor.Peek();
                FontStyle fs = 0;
                if(Bold){
                    fs |= FontStyle.Bold;
                }
                if(Italic){
                    fs |= FontStyle.Italic;
                }
                if(Underline){
                    fs |= FontStyle.Underline;
                }
                var font = new Font(FontName, FontSize, fs);
                Element.Font = font;
                Element.BackColor = BackColor;
                Element.ForeColor = ForeColor1;
                Element.Link = Link;
                Element.Effect = Effect;
                Element.EffectColor = EffectColor;
            }
        }
        private bool IsIndex(string src)
        {
            int i;
            return int.TryParse(src, out i);
        }
        private void CreateWords(Element[] Elements)
        {
            var bbuff = new GDISurface(1, 1, this, false);
            this._HasImageError = false;
            foreach(Element Element in Elements){
                if(Element.TagName == "img"){
                    Element.words = new Word[1];
                    Element.words[0] = new Word();
                    Image img = null;
                    try{
                        string SRC = this.GetAttrib("img", Element.Tag).ToLowerInvariant();
                        if(this.IsIndex(SRC)){
                            int index = int.Parse(SRC);
                            img = this.ImageList.Images[index];
                        } else if(SRC.StartsWith("http://")) //from url
                        {} else if(SRC.StartsWith("file://")) // from file
                        {
                            img = Image.FromFile(SRC.Substring(7));
                        } else //from file
                        {
                            img = Image.FromFile(SRC);
                        }
                    } catch{
                        img = new Bitmap(20, 20);
                        this._HasImageError = true;
                    }
                    Element.words[0].Image = img;
                    Element.words[0].Element = Element;
                    if(img != null){
                        Element.words[0].Height = img.Height;
                        Element.words[0].Width = img.Width;
                        Element.words[0].ScreenArea.Width = img.Width;
                        Element.words[0].ScreenArea.Height = img.Height;
                    }
                } else{
                    string[] words = Element.Text.Split(' ');
                    Element.words = new Word[words.Length];
                    int i = 0;
                    foreach(string word in words){
                        Element.words[i] = new Word();
                        string tmp;
                        Element.words[i].Element = Element;
                        if(i == words.Length - 1){
                            Element.words[i].Text = word;
                            tmp = word;
                        } else{
                            Element.words[i].Text = word + " ";
                            tmp = word + " "; //last space cant be measured , lets measure an "," instead
                        }
                        //SizeF size=g.MeasureString (tmp,Element.Font);
                        bbuff.Font = this.GetFont(Element.Font);
                        Size s = bbuff.MeasureTabbedString(tmp, 0);
                        Element.words[i].Height = s.Height;
                        Element.words[i].Width = s.Width - 0;
                        Element.words[i].ScreenArea.Width = Element.words[i].Width;
                        Element.words[i].ScreenArea.Height = Element.words[i].Height;
                        //	Element.words[i].Link =Element.Link ;
                        i++;
                    }
                }
            }
            bbuff.Dispose();
        }
        private GDIFont GetFont(Font font)
        {
            GDIFont gf = null;
            if(!this._Fonts.TryGetValue(this.GetFontKey(font), out gf)){
                gf = new GDIFont(font.Name, font.Size, font.Bold, font.Italic, font.Underline, false);
                this._Fonts[this.GetFontKey(font)] = gf;
            }
            return gf;
        }
        private string GetFontKey(Font font)
        {
            return font.Name + font.Bold + font.Italic + font.Underline + font.Size;
        }
        private void CreateRows()
        {
            if(this._Elements != null){
                int x = 0;
                this._Rows = new List<Row>();
                //build rows---------------------------------------------
                var row = new Row();
                this._Rows.Add(row);
                bool WhiteSpace = false;
                foreach(Element Element in this._Elements){
                    if(Element.words == null){
                        return;
                    }
                    if(Element.NewLine){
                        //tag forces a new line
                        x = 0;
                        row = new Row();
                        this._Rows.Add(row);
                        WhiteSpace = true;
                    }
                    if(Element.TagName == "hr"){
                        row.RenderSeparator = true;
                    }
                    //else
                    //{
                    foreach(Word word in Element.words){
                        if(this.WordWrap){
                            int scrollwdh = 0;
                            if(this.ScrollBars == ScrollBars.Both || this.ScrollBars == ScrollBars.Vertical){
                                scrollwdh = this.vScroll.Width;
                            }
                            if((word.Width + x) > this.ClientWidth - this.Margin - scrollwdh){
                                //new line due to wordwrap
                                x = 0;
                                row = new Row();
                                this._Rows.Add(row);
                                WhiteSpace = true;
                            }
                        }
                        if(word.Text.Replace(" ", "") != "" || word.Image != null){
                            WhiteSpace = false;
                        }
                        if(!WhiteSpace){
                            row.Words.Add(word);
                            x += word.Width;
                        }
                    }
                    //}
                }
                //apply width and height to all rows
                int index = 0;
                foreach(Row r in this._Rows){
                    int width = 0;
                    int height = 0;
                    int padd = 0;
                    if(index > 0){
                        int previndex = index - 1;
                        Row prev = this._Rows[previndex];
                        while(previndex >= 0 && prev.Words.Count == 0){
                            prev = this._Rows[previndex];
                            previndex--;
                        }
                        if(previndex >= 0){
                            prev = this._Rows[previndex];
                            if(prev.Words.Count > 0){
                                Word w = prev.Words[prev.Words.Count - 1];
                                height = w.Height;
                            }
                        }
                    }
                    foreach(Word w in r.Words){
                        if(w.Height > height && (w.Text != "")){
                            height = w.Height;
                        }
                        width += w.Width;
                    }
                    r.Height = height;
                    int MaxImageH = 0;
                    foreach(Word w in r.Words){
                        if(w.Image != null){
                            if(w.Height > height){
                                MaxImageH = w.Height;
                            }
                        }
                    }
                    foreach(Word w in r.Words){
                        int imgH = 0;
                        int imgPadd = 0;
                        if(w.Image != null){
                            string valign = this.GetAttrib("valign", w.Element.Tag);
                            switch(valign){
                                case "top":
                                {
                                    imgH = r.Height;
                                    imgPadd = w.Height - imgH;
                                    break;
                                }
                                case "middle":
                                case "center":
                                {
                                    imgH = r.Height;
                                    int tmp = (w.Height - imgH) / 2;
                                    imgH += tmp;
                                    imgPadd = tmp;
                                    break;
                                }
                                case "bottom":
                                {
                                    imgH = w.Height;
                                    imgPadd = 0;
                                    break;
                                }
                                default:
                                {
                                    imgH = w.Height;
                                    imgPadd = 0;
                                    break;
                                }
                            }
                            if(imgH > height){
                                height = imgH;
                            }
                            if(imgPadd > padd){
                                padd = imgPadd;
                            }
                            width += w.Width;
                        }
                    }
                    r.Width = width;
                    r.Height = height;
                    r.BottomPadd = padd;
                    index++;
                }
                this.vScroll.Maximum = this._Rows.Count;
            }
        }
        private void InitScrollbars()
        {
            if(this.vScroll == null || this.hScroll == null){
                return;
            }
            if(this.ScrollBars == ScrollBars.Both){
                this.vScroll.Left = this.ClientWidth - this.vScroll.Width;
                this.vScroll.Top = 0;
                this.vScroll.Height = this.ClientHeight - this.hScroll.Height;
                this.hScroll.Left = 0;
                this.hScroll.Top = this.ClientHeight - this.hScroll.Height;
                this.hScroll.Width = this.ClientWidth - this.vScroll.Width;
                this.Filler.Left = this.vScroll.Left;
                this.Filler.Top = this.hScroll.Top;
                this.Filler.Visible = true;
                this.vScroll.Visible = true;
                this.hScroll.Visible = true;
            } else if(this.ScrollBars == ScrollBars.Vertical){
                this.vScroll.Left = this.ClientWidth - this.vScroll.Width;
                this.vScroll.Top = 0;
                this.vScroll.Height = this.ClientHeight;
                this.hScroll.Left = 0;
                this.hScroll.Top = this.ClientHeight - this.hScroll.Height;
                this.hScroll.Width = this.ClientWidth - this.vScroll.Width;
                this.Filler.Left = this.vScroll.Left;
                this.Filler.Top = this.hScroll.Top;
                this.Filler.Visible = false;
                this.vScroll.Visible = true;
                this.hScroll.Visible = false;
            } else if(this.ScrollBars == ScrollBars.Horizontal){
                this.vScroll.Left = this.ClientWidth - this.vScroll.Width;
                this.vScroll.Top = 0;
                this.vScroll.Height = this.ClientHeight;
                this.hScroll.Left = 0;
                this.hScroll.Top = this.ClientHeight - this.hScroll.Height;
                this.hScroll.Width = this.ClientWidth;
                this.Filler.Left = this.vScroll.Left;
                this.Filler.Top = this.hScroll.Top;
                this.Filler.Visible = false;
                this.vScroll.Visible = false;
                this.hScroll.Visible = true;
            } else if(this.ScrollBars == ScrollBars.None){
                this.vScroll.Left = this.ClientWidth - this.vScroll.Width;
                this.vScroll.Top = 0;
                this.vScroll.Height = this.ClientHeight;
                this.hScroll.Left = 0;
                this.hScroll.Top = this.ClientHeight - this.hScroll.Height;
                this.hScroll.Width = this.ClientWidth;
                this.Filler.Left = this.vScroll.Left;
                this.Filler.Top = this.hScroll.Top;
                this.Filler.Visible = false;
                this.vScroll.Visible = false;
                this.hScroll.Visible = false;
            }
        }
        protected override void OnResize(EventArgs e)
        {
            try{
                this.InitScrollbars();
                this.SetAutoSize();
            } catch{}
            this.CreateRows();
            base.OnResize(e);
        }
        protected override void OnMouseUp(MouseEventArgs e)
        {
            int y = e.Y;
            int x = e.X;
            int index = 0;
            bool Link = false;
            //this.Cursor =Cursors.Arrow;
            this._ActiveElement = null;
            if(this._Rows != null){
                foreach(Row r in this._Rows){
                    if(y >= r.Top && y <= r.Top + r.Height){
                        foreach(Word w in r.Words){
                            if(y >= w.ScreenArea.Top && y <= w.ScreenArea.Bottom){
                                if(x >= w.ScreenArea.Left && x <= w.ScreenArea.Right){
                                    if(w.Element.Link != null){
                                        Link = true;
                                        this._ActiveElement = w.Element.Link;
                                        break;
                                    }
                                }
                            }
                        }
                        break;
                    }
                    index++;
                }
            }
            if(Link){
                this.Cursor = Cursors.Hand;
                this.Invalidate();
                this.OnClickLink(this.GetAttrib("href", this._ActiveElement.Tag));
            } else{
                this.Cursor = Cursors.Arrow;
                this.Invalidate();
            }
            base.OnMouseUp(e);
        }
        protected override void OnMouseMove(MouseEventArgs e)
        {
            int y = e.Y;
            int x = e.X;
            int index = 0;
            bool Link = false;
            //this.Cursor =Cursors.Arrow;
            this._ActiveElement = null;
            if(this._Rows != null){
                foreach(Row r in this._Rows){
                    if(y >= r.Top && y <= r.Top + r.Height){
                        foreach(Word w in r.Words){
                            if(y >= w.ScreenArea.Top && y <= w.ScreenArea.Bottom){
                                if(x >= w.ScreenArea.Left && x <= w.ScreenArea.Right){
                                    if(w.Element.Link != null){
                                        Link = true;
                                        this._ActiveElement = w.Element.Link;
                                        break;
                                    }
                                }
                            }
                        }
                        break;
                    }
                    index++;
                }
            }
            if(Link){
                this.Cursor = Cursors.Hand;
                this.Invalidate();
            } else{
                this.Cursor = Cursors.Arrow;
                this.Invalidate();
            }
            base.OnMouseMove(e);
        }
        private void vScroll_Scroll(object sender, ScrollEventArgs e)
        {
            this.Invalidate();
        }
        public int GetWidth()
        {
            int max = 0;
            foreach(Row r in this._Rows){
                if(r.Width > max){
                    max = r.Width;
                }
            }
            return max + this.Margin * 2 + this.BorderWidth * 2;
        }
        public int GetHeight()
        {
            int max = 0;
            foreach(Row r in this._Rows){
                max += r.Height;
            }
            return max + this.Margin * 2 + this.BorderWidth * 2;
        }

        #region PUBLIC PROPERTY MARGIN
        private int _Margin;
        public new int Margin
        {
            get { return this._Margin; }
            set
            {
                this._Margin = value;
                this.CreateRows();
                this.Invalidate();
            }
        }
        #endregion
    }
}